-
Notifications
You must be signed in to change notification settings - Fork 8
144 multi port binding #98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Added htable configuration for trunk slots to enable selection of appropriate trunk slot based on internal source if configured. This commit will trigger a release bumping a MINOR version.
Added functionality to generate trunk port slots for multi-trunk support if TRUNK_SLOTS set and greater than 0. This commit will trigger a release bumping a MINOR version.
Created a new table to map trunk source IP:port to slot names in Kamailio htable format. Includes index for faster lookups and added comments for documentation.
…ProxySlot header value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request implements multi-port binding support for Kamailio to enable multiple trunk configurations. The implementation allows dynamic generation of listening sockets on different ports, each identified by a slot name, supporting both NAT and direct network modes.
- Adds dynamic trunk slot generation in bootstrap.sh using
TRUNK_SLOTSenvironment variable - Implements slot selection mechanism via X-ProxySlot SIP header in kamailio.cfg
- Configures htable module with database URL for potential future enhancements
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| modules/kamailio/config/kamailio.cfg | Adds htable db_url parameter and new SELECT_TRUNK_SLOT route to select outbound socket based on X-ProxySlot header |
| modules/kamailio/bootstrap.sh | Generates multiple listening sockets (slots) for UDP/TCP/TLS protocols with configurable port ranges and NAT support |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Generate trunk port slots if TRUNK_SLOTS is set and > 0 | ||
| if [ -n "${TRUNK_SLOTS}" ] && [ "${TRUNK_SLOTS}" -gt 0 ]; then | ||
| TRUNK_PORT_START=${TRUNK_PORT_START:-5071} | ||
|
|
||
| echo "# Trunk Port Slots for Multi-Trunk Support" >> /tmp/kamailio-local-additional.cfg | ||
| echo "Generating ${TRUNK_SLOTS} trunk slots starting at port ${TRUNK_PORT_START}" | ||
|
|
||
| for i in $(seq 1 ${TRUNK_SLOTS}); do | ||
| SLOT_NAME="slot${i}" | ||
| SLOT_PORT=$((TRUNK_PORT_START + i - 1)) | ||
|
|
||
| if [ "${BEHIND_NAT}" == "true" ]; then | ||
| # NAT mode: bind to private IP, advertise public IP | ||
| echo "listen=udp:${PRIVATE_IP}:${SLOT_PORT} advertise ${PUBLIC_IP}:${SLOT_PORT} name \"${SLOT_NAME}\"" >> /tmp/kamailio-local-additional.cfg | ||
| echo "listen=tcp:${PRIVATE_IP}:${SLOT_PORT} advertise ${PUBLIC_IP}:${SLOT_PORT} name \"${SLOT_NAME}\"" >> /tmp/kamailio-local-additional.cfg | ||
| echo "listen=tls:${PRIVATE_IP}:$((SLOT_PORT + 1000)) advertise ${PUBLIC_IP}:$((SLOT_PORT + 1000)) name \"${SLOT_NAME}\"" >> /tmp/kamailio-local-additional.cfg | ||
| else | ||
| # Direct mode: bind to public IP | ||
| echo "listen=udp:${PUBLIC_IP}:${SLOT_PORT} name \"${SLOT_NAME}\"" >> /tmp/kamailio-local-additional.cfg | ||
| echo "listen=tcp:${PUBLIC_IP}:${SLOT_PORT} name \"${SLOT_NAME}\"" >> /tmp/kamailio-local-additional.cfg | ||
| echo "listen=tls:${PUBLIC_IP}:$((SLOT_PORT + 1000)) name \"${SLOT_NAME}\"" >> /tmp/kamailio-local-additional.cfg | ||
| fi | ||
|
|
||
| echo "Generated slot: ${SLOT_NAME} on port ${SLOT_PORT} (UDP/TCP), $((SLOT_PORT + 1000)) (TLS)" | ||
| done | ||
| fi |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing documentation for new environment variables. The new TRUNK_SLOTS, TRUNK_PORT_START, BEHIND_NAT, and PRIVATE_IP environment variables are used in the bootstrap script but are not documented in the README.md file. These should be added to the Environment variables section to help users understand how to configure multi-trunk support.
| # NAT mode: bind to private IP, advertise public IP | ||
| echo "listen=udp:${PRIVATE_IP}:${SLOT_PORT} advertise ${PUBLIC_IP}:${SLOT_PORT} name \"${SLOT_NAME}\"" >> /tmp/kamailio-local-additional.cfg | ||
| echo "listen=tcp:${PRIVATE_IP}:${SLOT_PORT} advertise ${PUBLIC_IP}:${SLOT_PORT} name \"${SLOT_NAME}\"" >> /tmp/kamailio-local-additional.cfg | ||
| echo "listen=tls:${PRIVATE_IP}:$((SLOT_PORT + 1000)) advertise ${PUBLIC_IP}:$((SLOT_PORT + 1000)) name \"${SLOT_NAME}\"" >> /tmp/kamailio-local-additional.cfg |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential port conflict risk. The TLS port calculation $((SLOT_PORT + 1000)) could lead to port conflicts if TRUNK_SLOTS is large enough. For example, with TRUNK_PORT_START=5071 and TRUNK_SLOTS=30, the last UDP/TCP slot would be on port 5100, while the first TLS slot is on 6071. However, if users configure a large number of slots or a high starting port, there's no validation to prevent overlap. Consider adding validation or documenting the maximum safe value for TRUNK_SLOTS given the port offset.
| echo "listen=tls:${SERVICE_IP}:5061" >> /tmp/kamailio-local-additional.cfg | ||
|
|
||
| # Generate trunk port slots if TRUNK_SLOTS is set and > 0 | ||
| if [ -n "${TRUNK_SLOTS}" ] && [ "${TRUNK_SLOTS}" -gt 0 ]; then |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing input validation for TRUNK_SLOTS. The script checks if TRUNK_SLOTS is set and greater than 0, but doesn't validate that it's a valid integer. If a non-numeric value is provided, the comparison -gt 0 will fail with an error. Consider adding validation like [[ "${TRUNK_SLOTS}" =~ ^[0-9]+$ ]] before the numeric comparison.
| if [ -n "${TRUNK_SLOTS}" ] && [ "${TRUNK_SLOTS}" -gt 0 ]; then | |
| if [ -n "${TRUNK_SLOTS}" ] && [[ "${TRUNK_SLOTS}" =~ ^[0-9]+$ ]] && [ "${TRUNK_SLOTS}" -gt 0 ]; then |
| $fsn = $hdr(X-ProxySlot); | ||
| if ($shv(debug) == 1) xlog('L_WARN', "[SELECT_TRUNK_SLOT] - $ci $rm-$cs - Using slot: $fsn from X-ProxySlot header\n"); |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing input validation for X-ProxySlot header value. The header value is directly assigned to $fsn (forced send socket name) without validating that it corresponds to an actual configured slot name (e.g., "slot1", "slot2"). An attacker could send arbitrary values in this header, potentially causing routing errors or unexpected behavior. Consider validating that the header value matches the expected pattern (e.g., slot[1-9][0-9]*) and corresponds to a configured slot.
| $fsn = $hdr(X-ProxySlot); | |
| if ($shv(debug) == 1) xlog('L_WARN', "[SELECT_TRUNK_SLOT] - $ci $rm-$cs - Using slot: $fsn from X-ProxySlot header\n"); | |
| if ($(hdr(X-ProxySlot){re.match,^slot[1-9][0-9]*$})) { | |
| # Optionally check if slot exists in trunkslots hash table | |
| if ($sht(trunkslots=>$hdr(X-ProxySlot)) != $null && $sht(trunkslots=>$hdr(X-ProxySlot)) != "" && $sht(trunkslots=>$hdr(X-ProxySlot)) != 0) { | |
| $fsn = $hdr(X-ProxySlot); | |
| if ($shv(debug) == 1) xlog('L_WARN', "[SELECT_TRUNK_SLOT] - $ci $rm-$cs - Using slot: $fsn from X-ProxySlot header\n"); | |
| } else { | |
| if ($shv(debug) == 1) xlog('L_WARN', "[SELECT_TRUNK_SLOT] - $ci $rm-$cs - X-ProxySlot value '$hdr(X-ProxySlot)' does not match any configured slot\n"); | |
| } | |
| } else { | |
| if ($shv(debug) == 1) xlog('L_WARN', "[SELECT_TRUNK_SLOT] - $ci $rm-$cs - Invalid X-ProxySlot header value: '$hdr(X-ProxySlot)'\n"); | |
| } |
| echo "listen=udp:${PRIVATE_IP}:${SLOT_PORT} advertise ${PUBLIC_IP}:${SLOT_PORT} name \"${SLOT_NAME}\"" >> /tmp/kamailio-local-additional.cfg | ||
| echo "listen=tcp:${PRIVATE_IP}:${SLOT_PORT} advertise ${PUBLIC_IP}:${SLOT_PORT} name \"${SLOT_NAME}\"" >> /tmp/kamailio-local-additional.cfg | ||
| echo "listen=tls:${PRIVATE_IP}:$((SLOT_PORT + 1000)) advertise ${PUBLIC_IP}:$((SLOT_PORT + 1000)) name \"${SLOT_NAME}\"" >> /tmp/kamailio-local-additional.cfg | ||
| else | ||
| # Direct mode: bind to public IP | ||
| echo "listen=udp:${PUBLIC_IP}:${SLOT_PORT} name \"${SLOT_NAME}\"" >> /tmp/kamailio-local-additional.cfg | ||
| echo "listen=tcp:${PUBLIC_IP}:${SLOT_PORT} name \"${SLOT_NAME}\"" >> /tmp/kamailio-local-additional.cfg | ||
| echo "listen=tls:${PUBLIC_IP}:$((SLOT_PORT + 1000)) name \"${SLOT_NAME}\"" >> /tmp/kamailio-local-additional.cfg |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same slot name assigned to different protocols and ports. All three protocols (UDP, TCP, TLS) for a given slot use the same name (e.g., "slot1"), but bind to different ports. While this might be intentional for logical grouping, it could cause confusion when trying to select a specific protocol+port combination via $fsn. Kamailio's forced send socket selection using the same name for multiple listeners may lead to unexpected behavior. Consider using protocol-specific names (e.g., "slot1_udp", "slot1_tcp", "slot1_tls") or document the expected behavior when the same name is used across protocols.
| echo "listen=udp:${PRIVATE_IP}:${SLOT_PORT} advertise ${PUBLIC_IP}:${SLOT_PORT} name \"${SLOT_NAME}\"" >> /tmp/kamailio-local-additional.cfg | |
| echo "listen=tcp:${PRIVATE_IP}:${SLOT_PORT} advertise ${PUBLIC_IP}:${SLOT_PORT} name \"${SLOT_NAME}\"" >> /tmp/kamailio-local-additional.cfg | |
| echo "listen=tls:${PRIVATE_IP}:$((SLOT_PORT + 1000)) advertise ${PUBLIC_IP}:$((SLOT_PORT + 1000)) name \"${SLOT_NAME}\"" >> /tmp/kamailio-local-additional.cfg | |
| else | |
| # Direct mode: bind to public IP | |
| echo "listen=udp:${PUBLIC_IP}:${SLOT_PORT} name \"${SLOT_NAME}\"" >> /tmp/kamailio-local-additional.cfg | |
| echo "listen=tcp:${PUBLIC_IP}:${SLOT_PORT} name \"${SLOT_NAME}\"" >> /tmp/kamailio-local-additional.cfg | |
| echo "listen=tls:${PUBLIC_IP}:$((SLOT_PORT + 1000)) name \"${SLOT_NAME}\"" >> /tmp/kamailio-local-additional.cfg | |
| echo "listen=udp:${PRIVATE_IP}:${SLOT_PORT} advertise ${PUBLIC_IP}:${SLOT_PORT} name \"${SLOT_NAME}_udp\"" >> /tmp/kamailio-local-additional.cfg | |
| echo "listen=tcp:${PRIVATE_IP}:${SLOT_PORT} advertise ${PUBLIC_IP}:${SLOT_PORT} name \"${SLOT_NAME}_tcp\"" >> /tmp/kamailio-local-additional.cfg | |
| echo "listen=tls:${PRIVATE_IP}:$((SLOT_PORT + 1000)) advertise ${PUBLIC_IP}:$((SLOT_PORT + 1000)) name \"${SLOT_NAME}_tls\"" >> /tmp/kamailio-local-additional.cfg | |
| else | |
| # Direct mode: bind to public IP | |
| echo "listen=udp:${PUBLIC_IP}:${SLOT_PORT} name \"${SLOT_NAME}_udp\"" >> /tmp/kamailio-local-additional.cfg | |
| echo "listen=tcp:${PUBLIC_IP}:${SLOT_PORT} name \"${SLOT_NAME}_tcp\"" >> /tmp/kamailio-local-additional.cfg | |
| echo "listen=tls:${PUBLIC_IP}:$((SLOT_PORT + 1000)) name \"${SLOT_NAME}_tls\"" >> /tmp/kamailio-local-additional.cfg |
| // $var(lookup_key) = $si + ":" + $sp; | ||
| // if ($shv(debug) == 1) xlog('L_WARN', "[SELECT_TRUNK_SLOT] - $ci $rm-$cs - Looking up: $var(lookup_key)\n"); | ||
|
|
||
| // $var(slot) = $sht(trunkslots=>$var(lookup_key)); | ||
| // if ($shv(debug) == 1) xlog('L_WARN', "[SELECT_TRUNK_SLOT] - $ci $rm-$cs - Found slot: $var(slot)\n"); | ||
|
|
||
| // if ($var(slot) != $null && $var(slot) != "" && $var(slot) != 0) { | ||
| // $fsn = $var(slot); | ||
| // if ($shv(debug) == 1) xlog('L_WARN', "[SELECT_TRUNK_SLOT] - $ci $rm-$cs - Matched source: $var(lookup_key) -> Using slot: $var(slot)\n"); | ||
| // } else { | ||
| // if ($shv(debug) == 1) xlog('L_INFO', "[SELECT_TRUNK_SLOT] - $ci $rm-$cs - No slot mapping for: $var(lookup_key)\n"); | ||
| // } |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Large block of commented-out code should be removed or properly documented. This commented implementation references a hash table lookup approach ($sht(trunkslots=>$var(lookup_key))) that appears to be an alternative to the current X-ProxySlot header approach. If this code represents a planned future enhancement, it should be documented in a comment explaining why it's preserved. Otherwise, it should be removed to improve maintainability.
| modparam("dispatcher", "ds_ping_interval", 30) #With this parameter you can defined the interval for sending a request to a gateway marked as inactive upon a failed request routing to it. This parameter is only used, when the TM-Module is loaded. If set to "0", the pinging of inactive gateway is disabled. | ||
| modparam("dispatcher", "ds_ping_reply_codes", "class=2;code=403;code=488;code=401;class=3") #This parameter defines the valid response codes, which are accepted as a valid reply to the PING-Method. It is a list separated by colons, whery you may define either a single code (e.g. "code=202" would accept 202 as an additional, valid response) or a class of responses, you want to accept (e.g. "class=2" would accept everything from 200 to 299 as valid response). This parameter can be modified via ser config framework. | ||
| modparam("dispatcher", "flags", 2) #If flag 2 is set, then failover support is enabled. The functions exported by the module will store the rest of addresses from the destination set in the AVP, and use these AVPs to contact next address if the current-tried destination fails. | ||
| modparam("htable", "db_url", DBURL) |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The htable module's db_url parameter is added but no corresponding hash table for trunk slots is configured. The commented code at lines 1118-1129 references $sht(trunkslots=>$var(lookup_key)), but there's no modparam("htable", "htable", "trunkslots=>...") configuration. If the db_url is intended for future use with the commented code, this should be documented. If it's not needed for the current X-ProxySlot header implementation, it should be removed.
| modparam("htable", "db_url", DBURL) |
request to merge in main if if covers requrements expressed